# = Class ASTAccessVec
# Inherits from ASTExpression. Represents the implementation of an AST especifically designed
# for instructions that make a binary operation access (v[i])
# == Attributes inherited from ASTExpression
# node, children
# == Methods inherited from ASTExpression
# check(), run(), to_s_children(im)
class ASTAccessVec < ASTExpression
  # If the operation is 'v[i]', then this operand is 'v'
  attr_reader :lop
  # If the operation is 'v[i]', then this operand is 'i'
  attr_reader :access
  # Type of element returned by access to vector
  attr_reader :type
  # Array containing the real values of the range's indexes as follows:
  # * range[0] -> initial index
  # * range[1] -> final index
  attr_reader :range

  # Constructor of the class
  # === Parameters
  # * lop: If the operation is 'v[i]', then this operand is 'v'
  # * access: If the operation is 'v[i]', then this operand is 'i'
  def initialize lop, access
    @lop = lop
    @access = access
  end

  # Method to evaluate vector access
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the parent AST
  # === Return value
  # nil if executed with success or an error message
  def eval parent_sym_table, func_table
    msg = @lop.eval parent_sym_table, func_table
    if nil != msg
      return msg
    end
    msg = @access.eval parent_sym_table, func_table
    if nil != msg
      return msg
    end
    if 'vec' == @type

      # Top left delimitation of new matrix
      @range = @access.value.clone
      @range[0] = nil != @range[0] ? @range[0] - 1 : 0
      @range[1] = nil != @range[1] ? @range[1] - 1 : @lop.value.value.length - 1
      
      if @lop.value.value.length <= @range[0]
        return "Accediendo a la altura '#{@access.value[0]}' cuando el máximo es #{@lop.value.value.length} (#{error_location})"
      end
      if @lop.value.value.length <= @range[1]
        return "Accediendo al ancho '#{@access.value[1]}' cuando el máximo es #{@lop.value.value.length} (#{error_location})"
      end

      v = []
      for i in (@range[0]..@range[1])
        # ASTExpression.Vector.Array[Position]
        v.push @lop.value.value[i]
      end
      @value = Vector.new v
      @type = @value.type = @lop.type
    else
      # ASTExpression.Vector.Array[Position]
      if @access.value[0] > @lop.value.value.length
        return "Intentando acceder a elemento #{@access.value[0]} cuando el maximo es #{@lop.value.value.length} (#{error_location})"
      end
      @range = @access.value[0] - 1
      @value = @lop.value.value[@access.value[0] - 1]
    end
    nil
  end

  # Method to check the static correctitude of vector access
  # === Parameters
  # * parent_sym_table: Symbol table passed by the parent AST
  # * func_table: Function symbol table passed by the pare
  # * func_type: Type of valid return value
  # === Return value
  # nil if executed with success or an error message
  def check parent_sym_table, func_table, func_type
    if nil == @lop
      return "Error interno: ASTAccessVec sin operador izquierdo (#{error_location})"
    end
    if nil == @access
      return "Error interno: ASTAccessVec sin operador de acceso (#{error_location})"
    end

    msg = @lop.check parent_sym_table, func_table, func_type
    if nil != msg
      return msg
    end
    msg = @access.check parent_sym_table, func_table, func_type
    if nil != msg
      return msg
    end

    if @lop.type != 'vec'
      return "Tratando de acceder con operador de vector a '#{@lop.type}' (#{error_location})"
    end

    @type = 'range' == @access.type ? @lop.type : 'num'

    nil
  end

  # Returns the closest wrong token to the place were an error is generated
  def error_tk
    tk = @lop.error_tk
    if nil != tk
      return tk
    end
    nil != @access ? @access.error_tk : nil
  end

  # Creates a 'String' representation of the AST with 'i' identation spaces
  # === Parameters
  # * i: Identation with which the AST should be printed with
  def to_s i
    im = i + @@c
    output = "(Acceso de vector"
    output += "\n#{im}"
    output += @lop.to_s im
    output += "\n#{im}"
    output += @access.to_s im
    output += "\n#{i})"
  end
end